#pragma once

#include "util.hpp"
#include "logger.hpp"
#include "db.hpp"
#include "online.hpp"
#include <unordered_set>
#include <unordered_map>
#include <memory>

namespace liang
{
#define BOARD_ROW 15
#define BOARD_COL 15
#define CHESS_WHITE 1
#define CHESS_BLACK 2

    typedef enum
    {
        GAME_START,
        GAME_OVER
    } roomStatu;

    class room
    {
    public:
        using ptr = std::shared_ptr<room>;
        room(uint64_t room_id, userTable *user_tb, onlineManager *online_user)
            : _room_id(room_id), _statu(GAME_START), _player_count(0),
              _user_tb(user_tb), _online_user(online_user),
              _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))
        {
            DEBUG("%lu 房间被创建", _room_id);
        }
        ~room() { DEBUG("%lu 房间被销毁", _room_id); }

        uint64_t id() { return _room_id; }
        roomStatu statu() { return _statu; }
        int playCount() { return _player_count; }
        void addWhiteUser(uint64_t uid)
        {
            _white_id = uid;
            _player_count++;
        }
        void addBlackUser(uint64_t uid)
        {
            _black_id = uid;
            _player_count++;
        }
        uint64_t getWhiteUser() { return _white_id; }
        uint64_t getBlackUser() { return _black_id; }

        // 总的请求处理函数, 在函数内部,区分请求类型,根据不同请求调用不同函数,然后将响应广播
        void handleRequest(Json::Value &req)
        {
            Json::Value resp;
            // 判断请求房间号是否与当前房间的房间号匹配
            uint64_t room_id = req["room_id"].asUInt64();
            if (_room_id != room_id)
            {
                resp["optype"] = req["optype"].asString();
                resp["result"] = false;
                resp["reason"] = "房间号不匹配";
            }
            else
            {
                // 根据请求类型调用不同的处理函数
                if (req["optype"].asString() == "put_chess")
                {
                    resp = handleChess(req);
                    if (resp["winner"].asInt64() != 0)
                    {
                        uint64_t winnerId = resp["winner"].asInt64();
                        uint64_t loserId = winnerId == _white_id ? _black_id : _white_id;
                        _user_tb->win(winnerId);
                        _user_tb->lose(loserId);
                        _statu = GAME_OVER;
                    }
                }
                else if (req["optype"].asString() == "chat")
                {
                    resp = handleChat(req);
                }
                else
                {
                    resp["optype"] = req["optype"].asString();
                    resp["result"] = false;
                    resp["reason"] = "未知消息类型";
                }
            }
            broadcast(resp);
        }
        // 处理下棋动作
        Json::Value handleChess(Json::Value &req)
        {
            Json::Value resp = req;

            if (_statu == GAME_OVER)
            {
                resp["result"] = false;
                resp["reason"] = "游戏已结束";
                resp["winner"] = 0;
                return resp;
            }

            uint64_t uid = req["uid"].asUInt64();
            int row = req["row"].asInt();
            int col = req["col"].asInt();
            // 判断玩家是否在线
            if (_online_user->isInRoom(_white_id) == false)
            {
                resp["result"] = true;
                resp["reason"] = "对方逃跑了";
                resp["winner"] = (Json::UInt64)_black_id;
                return resp;
            }
            if (_online_user->isInRoom(_black_id) == false)
            {
                resp["result"] = true;
                resp["reason"] = "对方逃跑了";
                resp["winner"] = (Json::UInt64)_white_id;
                return resp;
            }
            // 获取走棋位置
            if (row < 0 || row >= BOARD_ROW || col < 0 || col >= BOARD_COL)
            {
                resp["result"] = false;
                resp["reason"] = "无效的棋盘位置";
                resp["winner"] = 0;
                return resp;
            }

            if (_board[row][col] != 0)
            {
                resp["result"] = false;
                resp["reason"] = "当前位置已经有棋子了";
                resp["winner"] = 0;
                return resp;
            }

            // 判断是否胜利
            int color = (uid == _white_id ? CHESS_WHITE : CHESS_BLACK);
            _board[row][col] = color;
            uint64_t winnerId = checkWin(color, row, col);

            if (winnerId != 0)
            {
                resp["reason"] = "五星连珠";
            }
            else
            {
                resp["reason"] = "无人胜出, 游戏继续";
            }

            resp["result"] = true;
            resp["winner"] = (Json::UInt64)winnerId;
            return resp;
        }
        // 处理聊天动作
        Json::Value handleChat(Json::Value &req)
        {
            Json::Value resp = req;
            // 检测消息中是否含有敏感词
            std::string msg = req["message"].asString();
            if (!isLegitMsg(msg))
            {
                resp["result"] = false;
                resp["reason"] = "消息中含有敏感词";
                return resp;
            }
            else
            {
                resp["result"] = true;
                resp["reason"] = "消息合法";
            }
            return resp;
        }
        // 处理退出动作
        void handleExit(uint64_t uid)
        {
            Json::Value resp;
            if (_statu == GAME_START)
            {
                resp["optype"] = "put_chess";
                resp["result"] = true;
                resp["reason"] = "对方逃跑了";
                resp["room_id"] = (Json::UInt64)_room_id;
                resp["uid"] = uid;
                resp["row"] = -1;
                resp["col"] = -1;
                resp["winner"] = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);
                uint64_t winnerId = (uid == _white_id ? _black_id : _white_id);
                uint64_t loserId = winnerId == _white_id ? _black_id : _white_id;
                _user_tb->win(winnerId);
                _user_tb->lose(loserId);
                _statu = GAME_OVER;
                broadcast(resp);
                DEBUG("玩家[%lu]获胜, 玩家[%lu]失败", winnerId, loserId);
            }
            _player_count--;
        }
        // 将响应广播
        void broadcast(Json::Value &resp)
        {
            // 序列化
            std::string body;
            JsonHelper::serialize(resp, body);
            // 获取连接
            websocket_server::connection_ptr whiteConn = _online_user->getConnFromRoom(_white_id);
            websocket_server::connection_ptr blackConn = _online_user->getConnFromRoom(_black_id);
            // 发送响应
            if (whiteConn != nullptr)
            {
                whiteConn->send(body);
            }
            if (blackConn != nullptr)
            {
                blackConn->send(body);
            }
        }

    private:
        bool five(int color, int row, int col, int rowOff, int colOff)
        {
            int count = 1;
            int searchRow = row + rowOff;
            int searchCol = col + colOff;
            while (searchRow >= 0 && searchRow < BOARD_ROW &&
                   searchCol >= 0 && searchCol < BOARD_COL &&
                   _board[searchRow][searchCol] == color)
            {
                count++;
                searchRow += rowOff;
                searchCol += colOff;
            }

            searchRow = row - rowOff;
            searchCol = col - colOff;
            while (searchRow >= 0 && searchRow < BOARD_ROW &&
                   searchCol >= 0 && searchCol < BOARD_COL &&
                   _board[searchRow][searchCol] == color)
            {
                count++;
                searchRow -= rowOff;
                searchCol -= colOff;
            }

            return count >= 5;
        }
        uint64_t checkWin(int color, int row, int col)
        {
            if (five(color, row, col, 1, 0) ||
                five(color, row, col, 0, 1) ||
                five(color, row, col, 1, 1) ||
                five(color, row, col, 1, -1))
                return color == CHESS_WHITE ? _white_id : _black_id;
            return 0;
        }

        bool isLegitMsg(const std::string &msg)
        {
            for (const auto &word : _sensitive_words)
            {
                if (msg.find(word) != std::string::npos)
                {
                    return false;
                }
            }
            return true;
        }

    private:
        uint64_t _room_id;
        roomStatu _statu;
        int _player_count;
        uint64_t _white_id;
        uint64_t _black_id;
        userTable *_user_tb;         // 由外部管理生命周期，本类不负责释放
        onlineManager *_online_user; // 由外部管理生命周期，本类不负责释放
        std::vector<std::vector<int>> _board;

        std::unordered_set<std::string> _sensitive_words = {"垃圾"};
    };

    class roomManager
    {
    public:
        roomManager(userTable *tb_user, onlineManager *online_user)
            : _next_id(1), _tb_user(tb_user), _online_user(online_user)
        {
            DEBUG("房间管理模块初始化完毕");
        }
        ~roomManager()
        {
            DEBUG("房间管理模块销毁");
        }

        room::ptr createRoom(uint64_t uid1, uint64_t uid2)
        {
            // 判断是否在游戏大厅
            if (!_online_user->isInHall(uid1) || !_online_user->isInHall(uid2))
            {
                DEBUG("玩家[%lu或%lu]不在大厅中", uid1, uid2);
                return nullptr;
            }

            std::unique_lock<std::mutex> lock(_mutex);
            // 创建房间
            room::ptr rp(new room(_next_id, _tb_user, _online_user));
            rp->addWhiteUser(uid1);
            rp->addBlackUser(uid2);
            // 将房间管理起来
            _rooms.insert(std::make_pair(_next_id, rp));
            _users.insert(std::make_pair(uid1, _next_id));
            _users.insert(std::make_pair(uid2, _next_id));

            _next_id++;
            return rp;
        }

        room::ptr getRoomByRid(uint64_t rid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _rooms.find(rid);
            if (it == _rooms.end())
            {
                DEBUG("房间[%lu]不存在", rid);
                return nullptr;
            }
            return it->second;
        }

        room::ptr getRoomByUid(uint64_t uid)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto uit = _users.find(uid);
            if (uit == _users.end())
            {
                DEBUG("玩家[%lu]没有在游戏房间中", uid);
                return nullptr;
            }

            auto rit = _rooms.find(uit->second);
            if (rit == _rooms.end())
            {
                DEBUG("玩家[%lu]所在的房间[%lu]不存在", uid, uit->second);
                return nullptr;
            }
            return rit->second;
        }

        void removeRoom(uint64_t rid)
        {
            room::ptr rp = getRoomByRid(rid);
            if (rp == nullptr)
            {
                DEBUG("房间[%lu]不存在", rid);
                return;
            }
                
            // 获取玩家的id
            uint64_t uid1 = rp->getWhiteUser();
            uint64_t uid2 = rp->getBlackUser();
            _users.erase(uid1);
            _users.erase(uid2);
            _rooms.erase(rid);
        }
        void removeRoomUser(uint64_t uid)
        {
            room::ptr rp = getRoomByUid(uid);
            if (rp == nullptr)
                return;

            rp->handleExit(uid);
            DEBUG("玩家[%lu]退出游戏房间[%lu], 房间剩余人数:%d", uid, rp->id(), rp->playCount());
            if (rp->playCount() == 0)
                removeRoom(rp->id());
        }

    private:
        std::mutex _mutex;
        uint64_t _next_id;
        userTable *_tb_user;
        onlineManager *_online_user;
        std::unordered_map<uint64_t, room::ptr> _rooms; // 房间号与房间的映射
        std::unordered_map<uint64_t, uint64_t> _users;  // 玩家编号与房间号的映射
    };
}